package menu;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;

import java.awt.Point;
import java.awt.event.MouseEvent;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;

import state.GameState;
import state.Profile;
import chesskers.Driver;
import chesskers.GamePiece;
import chesskers.GamePlayMouseListener;
import chesskers.ImagePanel;
import chesskers.UIManager;
import chesskers.GameTimer;

public abstract class GameDisplayPanel extends MenuWindow {

	ImagePanel gd_back_manPanel;

	private JLabel profile1Label, profile2Label;

	public JLabel profile1Time, profile2Time;

	private JMenuBar menuBar;
	private JMenu systemMenu, gameMenu;
	private JMenuItem systemSave, systemQuit, gameForfeit;

	public static int xOffset = 100;
	public static int yOffset = 33;
	public static int squareSize = 50;
	public static int boardSize = 8;

	public GameState state;

	Container contentPane;

	public JPanel createContentPane() {

		gd_back_manPanel.setLayout(null);

		JPanel textPanel = new JPanel();
		textPanel.setLayout(null);
		textPanel.setLocation(0, 0);
		textPanel.setSize(600, 500);
		textPanel.setOpaque(false);
		gd_back_manPanel.add(textPanel);

		profile1Label = new JLabel(state.player1.name, SwingConstants.LEFT);
		profile1Label.setForeground(Color.white);
		profile1Label.setLocation(-50, 250);
		profile1Label.setMinimumSize(new Dimension(200, 200));
		profile1Label.setSize(new Dimension(200, 200));
		profile1Label.setHorizontalAlignment(0);
		textPanel.add(profile1Label);

		profile1Time = new JLabel("", SwingConstants.LEFT);
		profile1Time.setForeground(Color.white);
		profile1Time.setLocation(-50, 270);
		profile1Time.setMinimumSize(new Dimension(200, 200));
		profile1Time.setSize(new Dimension(200, 200));
		profile1Time.setHorizontalAlignment(0);
		textPanel.add(profile1Time);

		profile2Label = new JLabel(state.player2.name, SwingConstants.RIGHT);
		profile2Label.setForeground(Color.white);
		profile2Label.setLocation(-50, -50);
		profile2Label.setMinimumSize(new Dimension(200, 200));
		profile2Label.setSize(new Dimension(200, 200));
		profile2Label.setHorizontalAlignment(0);
		textPanel.add(profile2Label);

		profile2Time = new JLabel("", SwingConstants.LEFT);
		profile2Time.setForeground(Color.white);
		profile2Time.setLocation(-50, -30);
		profile2Time.setMinimumSize(new Dimension(200, 200));
		profile2Time.setSize(new Dimension(200, 200));
		profile2Time.setHorizontalAlignment(0);
		textPanel.add(profile2Time);

		return gd_back_manPanel;
	}

	public GameDisplayPanel() {
		super("Chess-kers!");
		InstantiateState();
		InstantiateBackground();

		menuBar = new JMenuBar();
		systemMenu = new JMenu("System");
		gameMenu = new JMenu("Game");

		systemSave = new JMenuItem("Save Game");
		systemQuit = new JMenuItem("Quit Game");
		gameForfeit = new JMenuItem("Forfeit Game");

		menuBar.add(systemMenu);
		menuBar.add(gameMenu);

		systemMenu.add(systemSave);
		systemMenu.add(systemQuit);
		MakeButtonAction(systemQuit, "quit");
		MakeButtonAction(systemSave, "save");
		gameMenu.add(gameForfeit);
		MakeButtonAction(gameForfeit, "forfeit");

		this.setContentPane(createContentPane());

		this.pack();
		this.setLocationRelativeTo(null);
		this.setSize(600, 500);
		this.setVisible(true);

		this.setJMenuBar(menuBar);
		this.addMouseListener(new GamePlayMouseListener(this));

		if (state.timeLimit > 0) new GameTimer(this).start();
	}

	public void setupGameDisplayPanel() {
		contentPane = this.getContentPane();

		contentPane.setLayout(new BorderLayout());

		JPanel p = new JPanel();

		profile1Label.setText(Driver.p1.name);
		profile1Label.setForeground(Color.white);
		profile1Label.setAlignmentX(100);
		profile1Label.setAlignmentY(100);

		profile2Label.setText(Driver.p2.name);
		profile2Label.setForeground(Color.white);

		contentPane.add(gd_back_manPanel);

		contentPane.add(profile1Label);
		contentPane.add(profile2Label);

		pack();
		setSize(600, 500);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setLocationRelativeTo(null);
		setResizable(false);
		setVisible(true);
	}

	public void InstantiateState() {
		if (Driver.gameState == null) {
			state = new GameState();

			state.player1 = Driver.p1;
			state.player2 = Driver.p2;

			state.timeLimit = Driver.timeLimit;
			
			state.blackGoing = false;

			state.moveTo = new ArrayList<Point>();
			state.attackTo = new ArrayList<Point>();
			state.selectedX = -1;
			state.selectedY = -1;

			state.board = new GamePiece[boardSize][boardSize];
			for (int i = 0; i < boardSize; i++) {
				for (int k = 0; k < boardSize; k++) {
					state.board[i][k] = null;
				}
			}
			state.player1 = Driver.p1;
			state.player2 = Driver.p2;
			state.isLoaded = false;

			Driver.gameState = state;
		} else {
			this.state = Driver.gameState;
			this.state.isLoaded = true;
			Driver.gameState = null;
		}
	}

	public abstract void InstantiateBackground();

	public void MouseClickedBoard(MouseEvent e) {
		int x = e.getPoint().x;
		int y = e.getPoint().y;
		int gridX = (x - xOffset) / squareSize;
		int gridY = (y - yOffset) / squareSize - 1;

		if ((x - xOffset) < 0 || gridX >= boardSize) {
			gridX = -1;
		}
		if ((y - yOffset) < 0 || gridY >= boardSize) {
			gridY = -1;
		}

		if (gridX >= 0 && gridY >= 0) {
			ClickSquare(gridX, gridY);
		}
	}

	public void Victory(boolean winnerBlack, boolean forfeit) {
		if (winnerBlack) {
			JOptionPane.showMessageDialog(this, state.player2.name + " wins!");
		} else {
			JOptionPane.showMessageDialog(this, state.player1.name + " wins!");
		}
		GivePoints(winnerBlack, forfeit);
		EndGame();
	}

	public void EndGame() {
		Driver.gameState = null;
		Driver.p1 = null;
		Driver.p2 = null;
		Driver.state = Driver.state.MainMenu;
		new UIManager().start();
		dispose();
	}

	public abstract void GivePoints(boolean winnerBlack, boolean forfeit);


	@Override
	public void Action(String cmd) {
		// TODO Auto-generated method stub
		switch (cmd) {
		case "quit":
			System.exit(0);
			break;
		case "forfeit":
			String msg = "";
			if (state.blackGoing) {
				msg = "Quit and let " + state.player1.name + " win?";
			} else {
				msg = "Quit and let " + state.player2.name + " win?";
			}
			int dialogResult = JOptionPane.showConfirmDialog(null, msg,
					"Warning", JOptionPane.YES_NO_OPTION);
			if (dialogResult == JOptionPane.YES_OPTION) {
				Victory(!state.blackGoing, true);
			}
			break;
		case "save":
			String fName = JOptionPane.showInputDialog(this,
					"Please Input Saved File Name", null);
			try {
				FileOutputStream fOut;
				if (Driver.state == Driver.state.ChessGame)
					fOut = new FileOutputStream(fName + ".chesssave");
				else
					fOut = new FileOutputStream(fName + ".checksave");

				ObjectOutputStream out = new ObjectOutputStream(fOut);
				out.writeObject(state);
				out.close();
			} catch (IOException e) {
				JOptionPane.showMessageDialog(this, "Error saving game");
				JOptionPane.showMessageDialog(this, e.toString());
			}
			break;
		default:
			throw new UnsupportedOperationException("Invalid button code: "
					+ cmd);
		}
	}

	public void RedrawBoard() {
		gd_back_manPanel.ResetToBackground();
		for (int i = 0; i < boardSize; i++) {
			for (int j = 0; j < boardSize; j++) {
				if (state.board[i][j] != null) {
					if (state.board[i][j].pic == null)
						state.board[i][j].loadImage();
					gd_back_manPanel.AddImage(state.board[i][j].pic, xOffset
							+ (i * squareSize), yOffset + (j * squareSize));
				}
			}
		}
		if (state.selectedX != -1 && state.selectedY != -1) {
			gd_back_manPanel.AddImage(
					new ImageIcon("img/selected.png").getImage(), xOffset
							+ (state.selectedX * squareSize), yOffset
							+ (state.selectedY * squareSize));
		}
		for (int i = 0; i < state.moveTo.size(); i++) {
			gd_back_manPanel.AddImage(
					new ImageIcon("img/moveto.png").getImage(), xOffset
							+ (state.moveTo.get(i).x * squareSize), yOffset
							+ (state.moveTo.get(i).y * squareSize));
		}
		for (int i = 0; i < state.attackTo.size(); i++) {
			gd_back_manPanel.AddImage(
					new ImageIcon("img/attackto.png").getImage(), xOffset
							+ (state.attackTo.get(i).x * squareSize), yOffset
							+ (state.attackTo.get(i).y * squareSize));
		}
		gd_back_manPanel.repaint();
	}

	public void ClickSquare(int x, int y) {
		if (state.moveTo.contains(new Point(x, y))
				|| state.attackTo.contains(new Point(x, y))) {
			if (state.moveTo.contains(new Point(x, y))) {
				state.board = state.board[state.selectedX][state.selectedY]
						.moveTo(x, y, state.board);
			} else if (state.attackTo.contains(new Point(x, y))) {
				state.board = state.board[state.selectedX][state.selectedY]
						.attackTo(x, y, state.board);
			}
			state.moveTo = new ArrayList<Point>();
			state.attackTo = new ArrayList<Point>();

			state.selectedX = -1;
			state.selectedY = -1;

			state.blackGoing = !state.blackGoing;

			RedrawBoard();
		} else {
			if (state.board[x][y] != null
					&& state.board[x][y].isBlack == state.blackGoing) {
				state.selectedX = x;
				state.selectedY = y;

				state.moveTo = state.board[x][y]
						.getMovePossibilities(state.board);
				state.attackTo = state.board[x][y]
						.getAttackPossibilities(state.board);

				RedrawBoard();
			}
		}
	}

	public abstract void Tie();
}